<?php

namespace api\components;

use api\utils\LogUtil;

/**
 * TODO: too simple
 */
class Curl
{
    private $curl;

    public function __construct()
    {
        if (!$this->curl) {
            $this->curl = curl_init();
        }
        $defaultOptions = [
            CURLOPT_TIMEOUT => 60,
            CURLOPT_CONNECTTIMEOUT => 60,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => true,
        ];
        curl_setopt_array($this->curl, $defaultOptions);
    }

    public function getCurl()
    {
        return $this->curl;
    }

    public function get($url, $params = [], $options = [])
    {
        if (!empty($options)) {
            curl_setopt_array($this->curl, $options);
        }
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
        if (!empty($params)) {
            $url = $url . '?' . $this->buildQuery($params);
        }
        $response = $this->request($url, 'get');
        return $response;
    }

    public function post($url, $params, $options = [], $isJson = true)
    {
        if (!empty($options)) {
            $url = $url . '?' . http_build_query($options);
        }
        if ($isJson) {
            $params = json_encode($params);
            curl_setopt($this->curl, CURLOPT_HTTPHEADER, ['Content-type: application/json']);
        }
        $response = $this->request($url, 'post', $params);
        return $response;
    }

    private function request(string $url, string $method, $params = [])
    {
        $method = strtolower($method);
        $curl = $this->curl;
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        if ($method == 'post') {
            curl_setopt($curl, CURLOPT_POST, 1); //post提交方式
            curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
        }
        $response = curl_exec($curl);
        $message = [
            'url' => $url,
            'method' => $method,
            'params' => $params,
            'response' => $response,
            'code' => curl_getinfo($this->curl, CURLINFO_HTTP_CODE),
        ];
        LogUtil::warn($message, 'accessOut');
        $res = $response;
        try {
            $array = json_decode($response, true);
            if (json_last_error() == JSON_ERROR_NONE) {
                $res = $array;
            }
        } catch (\Throwable $th) {
            $res = $response;
        }

        return $res;
    }

    /**
     * 代替 http_build_query
     *
     * 原因：在 http_build_query 中，空数组和不传 key 是一样的
     */
    public function buildQuery($input, $numeric_prefix = '', $arg_separator = '&', $enc_type = 2, $keyvalue_separator = '=', $prefix = '')
    {
        if (is_array($input)) {
            $arr = [];
            foreach ($input as $key => $value) {
                $name = $prefix;
                if (strlen($prefix)) {
                    $name .= '[';
                    if (!is_numeric($key)) {
                        $name .= $key;
                    }
                    $name .= ']';
                } else {
                    if (is_numeric($key)) {
                        $name .= $numeric_prefix;
                    }
                    $name .= $key;
                }
                if ((is_array($value) || is_object($value)) && count($value)) {
                    $arr[] = $this->buildQuery(
                        $value,
                        $numeric_prefix,
                        $arg_separator,
                        $enc_type,
                        $keyvalue_separator,
                        $name
                    );
                } else {
                    if ($enc_type === 2) {
                        $arr[] = rawurlencode($name)
                            . $keyvalue_separator
                            . rawurlencode($value ?: '');
                    } else {
                        $arr[] = urlencode($name)
                            . $keyvalue_separator
                            . urlencode($value ?: '');
                    }
                }
            }
            return implode($arg_separator, $arr);
        } else {
            if ($enc_type === 2) {
                return rawurlencode($input);
            } else {
                return urlencode($input);
            }
        }
    }
}